package ms.maplestory.boot.world.field;

import ms.maplestory.boot.client.character.Char;
import ms.maplestory.boot.enums.FieldType;
import ms.maplestory.boot.world.field.objects.FieldObj;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import ms.maplestory.boot.util.Util;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

@Slf4j
@Getter
@Setter
public class Field {

    private int id;
    private FieldType type;
    private boolean town, swim, fly, reactorShuffle, expeditionOnly, partyOnly;
    private int returnMap, forcedReturn, fixedMobCapacity, createMobInterval, timeOut, timeLimit, lvLimit, lvForceMove,
            consumeItemCoolTime, link, vrTop, vrLeft, vrBottom, vrRight;
    private String onFirstUserEnter = "", onUserEnter = "", fieldScript = "";
    private double mobRate;
    private long fieldLimit;
    private int objectIdCounter = 1000000;

    private Set<Foothold> footholds;
    private Set<Portal> portals;
    private Map<Integer, FieldObj> fieldObjs;
    private List<Char> chars;


    public Field(int id) {
        this.id = id;
        this.footholds = new HashSet<>();
        this.portals = new HashSet<>();
        this.fieldObjs = new ConcurrentHashMap<>();
        this.chars = new CopyOnWriteArrayList<>();
    }

    public void addFoothold(Foothold foothold) {
        footholds.add(foothold);
    }

    public void addPortal(Portal portal) {
        portals.add(portal);
    }

    public void addLife(FieldObj fieldObj) {
        if (fieldObj.getObjectId() < 0) {
            fieldObj.setObjectId(getNewObjectID());
        }
        if (!fieldObjs.values().contains(fieldObj)) {
            fieldObjs.put(fieldObj.getObjectId(), fieldObj);
            fieldObj.setField(this);
        }
    }

    public int getNewObjectID() {
        return objectIdCounter++;
    }

    public Portal getPortalByName(String name) {
        return Util.findWithPred(getPortals(), portal -> portal.getPn().equals(name));
    }

    public Set<MobGen> getMobGens() {
        return getFieldObjsByClass(MobGen.class);
    }

    private <T> Set<T> getFieldObjsByClass(Class clazz) {
        return (Set<T>) getFieldObjs().values().stream()
                .filter(l -> l.getClass().equals(clazz))
                .collect(Collectors.toSet());
    }

    public void addChar(Char chr) {
        if (!getChars().contains(chr)) {
            getChars().add(chr);
        }
    }

    public void removeChar(Char chr) {
        getChars().remove(chr);
    }

    @Override
    public String toString() {
        return "" + getId();
    }
}
